package cmd

import (
	"dynamic-private/pkg/conf"
	"dynamic-private/pkg/errs"
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	"github.com/tristin2024/logs"
	"github.com/tristin2024/render"
	"xorm.io/xorm"
)

func init() {
	render.InjErr(errs.Messages)
}

func cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method

		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-requested-with, type")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
		c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
		c.Header("Access-Control-Allow-Credentials", "true")

		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}
		c.Next()
	}
}

func recover500(c *gin.Context) {
	defer func() {
		if r := recover(); r != nil {
			// debug.PrintStack()
			logs.Std.Error(r)
			render.ErrInternalServerError(c, "服务器内部错误")
			c.Abort()
		}
	}()
	c.Next()
}

var (
	ginProvide = func() *gin.Engine {
		if conf.Env == "prod" {
			gin.SetMode(gin.ReleaseMode)
		} else {
			gin.SetMode(gin.DebugMode)
		}
		engine := gin.Default()
		engine.HandleMethodNotAllowed = true
		engine.ForwardedByClientIP = true

		engine.Use(cors())
		engine.Use(recover500)

		engine.NoRoute(func(c *gin.Context) {
			render.ErrNotFound(c, "404 page not found")
		})
		engine.NoMethod(func(c *gin.Context) {
			render.ErrMethodNotAllowed(c, "405 method not allowed")
		})
		return engine
	}

	postgresqlProvide = func() *xorm.Engine {
		dbConfig := "user=%s password=%s dbname=%s host=%s port=%s sslmode=disable"
		dbConfig = fmt.Sprintf(dbConfig,
			conf.PostgreSQL.User,
			conf.PostgreSQL.Password,
			conf.PostgreSQL.DbDynamic,
			conf.PostgreSQL.Host,
			conf.PostgreSQL.Port,
		)
		engine, err := xorm.NewEngine("postgres", dbConfig)
		if err != nil {
			panic("postgres init failed:" + err.Error())
		}
		err = engine.Ping()
		if err != nil {
			panic(fmt.Sprintf("ping failed: %s", err.Error()))
		}
		return engine
	}

	redisProvide = func() *redis.Client {
		client := redis.NewClient(&redis.Options{
			Addr:     fmt.Sprintf("%s:%s", conf.Redis.Host, conf.Redis.Port),
			Password: conf.Redis.Password,
			DB:       conf.Redis.Db3,
		})
		err := client.Ping().Err()
		if err != nil {
			panic("redis init failed:" + err.Error())
		}
		return client
	}
)
